﻿using ImTools;
using NewLife.Reflection;
using Prism.Ioc;
using StarryEdge.Core;
using StarryEdge.Core.Attributes;
using StarryEdge.Core.Manager;
using StarryEdge.Core.Models;
using StarryEdge.Core.Plugin;
using StarryEdge.Model;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Remoting;
using System.Text;
using System.Threading.Tasks;

namespace StarryEdge.Domains
{
    public class ObjectContainer : IObjectManager
    {
        private static ConcurrentDictionary<string, PluginSingletonsModel> _singletons = new ConcurrentDictionary<string, PluginSingletonsModel>();
        private static List<TaskHandleModel> _event = new List<TaskHandleModel>();
        private IContainerExtension _containerExtension;
        public ObjectContainer(IContainerExtension containerExtension)
        {
            _containerExtension = containerExtension;
        }

        public IEnumerable<string> GetTaskNames()
        {
            foreach (TaskHandleModel c in _event)
            {
                yield return c.TaskName;
            }
            yield return "扫描线程";
        }

        public bool UpdateObject<T, TModel>(object source_obj)
        {
            if (!_singletons.ContainsKey(typeof(T).Name))
            {
                _containerExtension.Resolve<IStarryEdgeLog>()?.LogRun($"找不到[{typeof(T).Name}]对象", Core.Enums.LogLevel.Error);
                return false;
            }
            var kv = _singletons[typeof(T).Name];
            if (!kv.IsUpdate)
            {
                return true;
            }
            object obj = kv.Handle.Invoke(kv.Obj, new object[] { typeof(TModel).Name });
            if (obj != null)
            {
                kv.IsUpdate = true;
                UpdateValue(source_obj, obj);
                kv.SaveHandle.Invoke(kv.Obj, default);
                return true;
            }
            return true;
        }

        public bool CopyObject<T, TModel>(object source_obj)
        {
            if (!_singletons.ContainsKey(typeof(T).Name))
            {
                return default;
            }
            var kv =_singletons[typeof(T).Name];
            object obj = kv.Handle.Invoke(kv.Obj, new object[] { typeof(TModel).Name });
            if (obj != null)
            {
                UpdateValue(obj, source_obj);
                return true;
            }
            return false;
        }

        private void UpdateValue(object sourc, object target)
        {
            var objProper = target.GetType().GetProperties();
            foreach (var item in sourc.GetType().GetProperties())
            {
                objProper.Where(x => x.Name == item.Name).FirstOrDefault().SetValue(target, item.GetValue(sourc, null));
            }
        }

        public TaskHandleModel ResolveTask(string task_name) => _event.Where(x => x.TaskName == task_name).FirstOrDefault();

        private Dictionary<Type, string> _typeDictionary = new Dictionary<Type, string>() { { typeof(string), "Lable" }, { typeof(int), "Address" } };

        public bool Update(int type)
        {
            IPluginManager pluginManager = _containerExtension.Resolve<IPluginManager>();
            var starryEdgeLog = _containerExtension.Resolve<IStarryEdgeLog>();
            var dialogHost = _containerExtension.Resolve<IDialogHost>();
            if (type == 1)
            {
                try
                {
                    List<IPlugin> plugins = pluginManager.GetPlugins(x => x.PluginInfo.Type == 3);
                    foreach (var plugin in plugins)
                    {
                        Assembly assembly = plugin.LoadPlugin(starryEdgeLog);
                        var singleton = assembly.GetTypes().Where(t => t.IsClass && t.GetCustomAttribute<SingletonAttribute>() != null).ToList();
                        foreach (var item in singleton)
                        {
                            var ps = item.GetConstructors()[^1].GetParameters();
                            MethodInfo method = item.GetMethod("GetModel");
                            MethodInfo method_save = item.GetMethod("Save");
                            List<object> plist = new List<object>();
                            foreach (var p in ps)
                            {
                                object obj = _containerExtension.Resolve(p.ParameterType);
                                plist.Add(obj);
                            }
                            string iname = $"I{item.Name}";
                            Type interfaceName = item.GetInterface(iname);
                            object objectHandle = Activator.CreateInstance(item, plist.ToArray());
                            if (_singletons.ContainsKey(iname))
                            {
                                _singletons[iname].Obj = objectHandle;
                                _singletons[iname].Handle = method;
                                _singletons[iname].SaveHandle = method_save;
                                _singletons[iname].IsUpdate = true;
                                continue;
                            }
                            _singletons.TryAdd(iname, new PluginSingletonsModel() { 
                                Obj = objectHandle,
                                Handle = method,
                                IsUpdate = true,
                                SaveHandle = method_save,
                            });
                        }
                    }
                    starryEdgeLog.LogRun("数据源更新成功", Core.Enums.LogLevel.Success);
                    return true;
                }
                catch (Exception ex)
                {
                    dialogHost.DialogShow($"更新数据源异常：{ex}", Core.Enums.LogLevel.Error, hostDialog: Core.Enums.PopUpTypes.Global);
                }
            }
            else if (type == 2)
            {
                try
                {
                    List<IPlugin> plugins = pluginManager.GetPlugins(x => x.PluginInfo.Type == 2);
                    foreach (var plugin in plugins)
                    {
                        Assembly assembly = plugin.LoadPlugin(starryEdgeLog);
                        var handlerTypes = assembly.GetTypes().Where(t => t.IsClass && t.GetCustomAttribute<TaskClassAttribute>() != null).ToList();
                        foreach (var handlerType in handlerTypes)
                        {
                            MethodInfo method = handlerType.GetMethod("Handle");
                            var ps = handlerType.GetConstructors()[^1].GetParameters();
                            List<object> plist = new List<object>();
                            foreach (var p in ps)
                            {
                                plist.Add(_containerExtension.Resolve(p.ParameterType));
                            }
                            foreach (var item in _typeDictionary)
                            {
                                Type type1 = handlerType.MakeGenericType(item.Key);
                                var handler = Activator.CreateInstance(type1, plist.ToArray());
                                TaskClassAttribute taskClass = handlerType.GetCustomAttribute<TaskClassAttribute>();
                                TaskHandleModel model = _event.FirstOrDefault(x => x.TaskName == $"{taskClass.TaskName}{item.Value}");
                                if (model != null)
                                {
                                    model.TaskObject = handler;
                                    model.IsUpdate = true;
                                    model.Handle = handler.GetType().GetMethod("Handle");
                                }
                                else
                                {
                                    _event.Add(new TaskHandleModel()
                                    {
                                        TaskObject = handler,
                                        TaskName = $"{taskClass.TaskName}{item.Value}",
                                        Handle = handler.GetType().GetMethod("Handle")
                                    });
                                }
                            }
                        }
                    }
                    starryEdgeLog.LogRun("任务更新成功", Core.Enums.LogLevel.Success);
                    return true;
                }
                catch (Exception ex)
                {
                    dialogHost.DialogShow($"更新任务异常：{ex}", Core.Enums.LogLevel.Error, hostDialog: Core.Enums.PopUpTypes.Global);
                }
            }
            return false;
        }
    }
}
